<template>
    <div class="page">
        <p>数据中台需要的图表</p>
        <div id="container"></div>
    </div>
</template>
<script>
import * as d3 from "d3"
const PERDEG = Math.PI / 180 //1度代表的弧度
export default {
    created() {
        this.scaleRatio = 0.7 //默认的菱形里面的图形与菱形的间距
        this.rangeDeg = 140 //默认的菱形的顶部的角度
    },
    methods: {
        init() {
            let container = document.querySelector("#container")
            this.svgWidth = container.clientWidth
            this.svgHeight = container.clientHeight
            this.svg = d3
                .select("#container")
                .append("svg")
                .attr("width", this.svgWidth)
                .attr("height", this.svgHeight)
            //定义统一的 圆柱图标
            this.svg
                .append("symbol")
                .attr("id", "icon1")
                .attr("width", 128)
                .attr("height", 128)
                .attr("viewBox", "0 0 1024 1024")
                .each(function () {
                    d3.select(this)
                        .append("path")
                        .attr(
                            "d",
                            "M509.312 441.024c-263.04 0-476.16-42.24-476.16-94.08v338.56h952.32v-338.56c0 51.84-213.12 94.08-476.16 94.08z"
                        )
                        .attr("fill", "#f4ea2a")
                    d3.select(this)
                        .append("path")
                        .attr(
                            "d",
                            "M509.312 591.424c-263.04 0-476.16 42.24-476.16 94.08 0 3.84 1.28 7.68 3.2 10.88 27.52 46.72 228.48 83.2 472.96 83.2s445.44-36.48 472.96-83.2c1.92-3.2 3.2-7.04 3.2-10.88 0-51.84-213.12-94.08-476.16-94.08zM509.312 236.416c-263.04 0-476.16 42.24-476.16 94.08 0 3.84 1.28 7.68 3.2 10.88 27.52 46.72 228.48 83.2 472.96 83.2s445.44-36.48 472.96-83.2c1.92-3.2 3.2-7.04 3.2-10.88 0-51.84-213.12-94.08-476.16-94.08z"
                        )
                        .attr("fill", "#f4ea2a")
                })
            //画统一的菱形标志
            let r = 10, //暂定菱形的边长为10，然后依据此来计算坐标
                deg = (PERDEG * this.rangeDeg) / 2,
                x = r * Math.sin(deg),
                y = r * Math.cos(deg)
            this.svg
                .append("symbol")
                .attr("id", "diamond")
                .attr("width", 128)
                .attr("height", 128)
                .attr("viewBox", () => {
                    return `0 0 ${2 * x} ${2 * y}`
                })
                .append("polygon")
                .attr("points", () => {
                    return `${x},0 ${2 * x},${y} ${x},${2 * y} 0,${y}`
                })
                .attr("fill", "#F5F6F7")
            //定义可复用的文字背景底色
            let bgSymbol = this.svg
                .append("defs")
                .append("filter")
                .attr("id", "textBg")
                .attr("x", -0.2)
                .attr("y", -0.2)
                .attr("width", 1.4)
                .attr("height", 1.4)
            bgSymbol
                .append("feFlood")
                .attr("width", "100%")
                .attr("height", "100%")
                .attr("flood-color", "#6E7397")
                .attr("flood-opacity", "0.5")
            bgSymbol
                .append("feComposite")
                .attr("in", "SourceGraphic")
                .attr("operator", "over")
        },
        draw() {
            this.init()
            let pointsData3 = this.drawGroup(1, 450, 4, 3)
            let pointsData2 = this.drawGroup(0.9, 280, 4, 2)
            let pointsData1 = this.drawGroup(0.8, 130, 3, 1)
            let pointsData0 = this.drawGroup(0.7, 0, 3, 0)
            this.drawText(pointsData0,0)
            this.drawText(pointsData1,1)
            this.drawText(pointsData2,2)
            this.drawText(pointsData3,3)
            this.generaterLineData(
                pointsData0,
                pointsData1,
                pointsData2,
                pointsData3
            )
        },
        /**
         * ratio   菱形的宽度占整个svg宽度的百分比
         * yOffset 菱形在y轴方向的偏移量
         * max     菱形一排最多放几个图形
         * index   下标
         */
        drawGroup(ratio = 0.7, yOffset = 0, max = 3, index = 0) {
            let groupWidth = this.svgWidth * ratio,
                groupHeight =
                    groupWidth /
                    Math.tan(((this.rangeDeg / 2) * Math.PI) / 180),
                group = this.svg
                    .append("g")
                    .attr("class", `g${index}`)
                    .style(
                        "transform",
                        `translate(${this.svgWidth / 2}px,${yOffset}px)`
                    )

            group
                .append("use")
                .attr("width", groupWidth)
                .attr("height", groupHeight)
                .attr("xlink:href", "#diamond")
                .style("transform", `translate(${-groupWidth / 2}px,0)`)
            // let nodeData = [1, 2, 3, 4, 5, 6, 7, 8, 9]
            let points = this.createPoints(
                groupWidth /
                    2 /
                    Math.sin(((this.rangeDeg / 2) * Math.PI) / 180),
                max,
                this.scaleRatio
            )
            let gNodes = group
                .append("g")
                .style(
                    "transform",
                    `translate(0,${
                        (groupHeight * (1 - this.scaleRatio)) / 2
                    }px)`
                )
            gNodes
                .selectAll("use")
                .data(points)
                .join("use")
                .attr("xlink:href", "#icon1")
                .attr("width", 50)
                .attr("height", 50)
                .attr("x", (d, i) => {
                    return points[i].x - 25
                })
                .attr("y", (d, i) => {
                    return points[i].y - 25
                })
            // gNodes
            //     .selectAll("text")
            //     .data(points)
            //     .join("text")
            //     .attr("x", (d, i) => points[i].x)
            //     .attr("y", (d, i) => points[i].y)
            //     .attr("dy", -25)
            //     .attr("dx", -25)
            //     .style("font-size", "12px")
            //     .attr("fill", "#fff")
            //     .text("经济领域")
            //     .attr("filter", "url(#textBg)")
            return {
                points,
                xOffset:this.svgWidth / 2,
                yOffset:yOffset+(groupHeight * (1 - this.scaleRatio)) / 2
            }
        },
        drawText(pointsData,index) {
            this.svg
            .append('g')
                .attr('class',`gtext${index}`)
                .style('transform',`translate(${pointsData.xOffset}px,${pointsData.yOffset}px)`)
                .selectAll("text")
                .data(pointsData.points)
                .join("text")
                .attr("x", (d, i) => pointsData.points[i].x)
                .attr("y", (d, i) => pointsData.points[i].y)
                .attr("dy", -25)
                .attr("dx", -25)
                .style("font-size", "12px")
                .attr("fill", "#fff")
                .text((d,i)=>{
                    //这里到时候需要判断一下，如果没有就不渲染文字
                    //用点坐标和后端返回的数据对下标
                    return i%2===1? '经济领域':''
                })
                .attr("filter", "url(#textBg)")
        },
        /**
         * diamond_width 菱形的边长
         * max_ele   最多的行放置了多少个元素
         * scaleRatio 关乎到菱形里面的图案距离菱形的边框的距离
         */
        createPoints(diamond_width, max_ele = 3, scaleRatio = 0.7) {
            //因为要把元素放到菱形里面去，可以把菱形分割为上下两部分，但是我们画的时候是用三角形来画的，
            //所以要把菱形的边长扩大两倍，然后再根据具体的情况筛选哪些节点放到菱形里面去

            //定义一些常量，三角形再坐标轴里面开始的角度，三角形自身的角度
            const perDeg = Math.PI / 180,
                startDeg = 180 - this.rangeDeg / 2,
                rangeDeg = this.rangeDeg,
                /**算横向最大距离 */
                xWidth =
                    2 *
                    diamond_width *
                    Math.sin((rangeDeg * perDeg) / 2) *
                    2 *
                    scaleRatio,
                /**乘以0.7是为了把点放在菱形的内部，离菱形的边框留距离 */
                yWidth =
                    2 *
                    diamond_width *
                    Math.cos((rangeDeg * perDeg) / 2) *
                    scaleRatio
            let max = 2 * max_ele - 1,
                arr = [],
                minus = 0,
                diffX = xWidth / (max - 1) //每一行其实被分割成了长度相等 数量不同的线段

            for (let i = 0; i < max; i++) {
                //计算每次换行之后，Y轴方向的偏移量，因为每一行的Y坐标是一样的
                let diffY = (yWidth / (max - 1)) * i,
                    startX = -Math.tan(perDeg * startDeg) * diffY //每次换行之后 第一个元素的x坐标是多少，后续的元素只需要在它的x坐标上减去偏移量即可
                if (i >= max_ele) {
                    minus++
                }
                for (let j = 0; j <= i; j++) {
                    if (i < max_ele) {
                        arr.push({
                            x: startX - diffX * j,
                            y: diffY,
                        })
                    } else {
                        if (j > minus - 1 && i - j > minus - 1) {
                            arr.push({
                                x: startX - diffX * j,
                                y: diffY,
                            })
                        }
                    }
                }
            }
            return arr
        },
        /**
         * 这里只是把画连线的方法展示出来，具体应该哪些点之间有关系，应该看到时候的具体数据
         */
        generaterLineData(arr1, arr2, arr3, arr4) {
            let lineData = []
            lineData.push([
                { x: arr1.points[1].x, y: arr1.points[1].y + arr1.yOffset + 12.5 },//这个28.6244是菱形向下的偏移量
                { x: arr2.points[4].x, y: arr2.points[4].y + arr2.yOffset - 12.5 },//这个32.7136是菱形向下的偏移量
            ])
            console.log(arr2, arr3, arr4)
            this.drawLines(lineData)
        },
        drawLines(data) {
            let group = this.svg
                .append("g")
                .attr("class", "linksGroup")
                .style("transform", `translate(${this.svgWidth / 2}px,0px)`)
            group
                .selectAll(".link")
                .data(data)
                .join("path")
                .attr("class", "link")
                .attr(
                    "d",
                    d3
                        .linkVertical()
                        .source(d => d[0])
                        .target(d => d[1])
                        .x(d => {
                            return d.x
                        })
                        .y(d => d.y)
                )
                .attr("fill", "none")
                .attr("stroke-width", 1)
                // .attr('stroke-dasharray',0)
                .attr("stroke", "red")
        },
    },
    mounted() {
        this.draw()
    },
}
</script>
<style scoped>
#container {
    width: 840px;
    height: 748.36px;
    margin: 0 auto;
}
</style>
